﻿using System;
using System.Data;
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
using Epi.Data;

namespace CDC.SampleShell.Infrastructure
{
    /// <summary>
    /// Sends changeset messages to the server
    /// </summary>
    /// <remarks>
    /// Intended as a simple mechanism by which to send updates to a server in a MS-SQL server environmnent, and where no server process is available.
    /// </remarks>
    public sealed class ChangesetSender
    {
        private readonly IDbDriver _database;
        private readonly string _version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
        private readonly string _user = System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
        private readonly string _macAddress = CDC.SampleShell.Common.GetMacAddress();

        public ChangesetSender(IDbDriver database)
        {
            Contract.Requires(database != null);

            _database = database;
        }

        public Guid SendMessage(ChangesetType changesetType, string description, string recordId, int formId = -1, IDbTransaction transaction = null)
        {
            // pre
            Contract.Requires(!String.IsNullOrEmpty(description));
            Contract.Requires(!String.IsNullOrEmpty(recordId));
            Contract.Requires(formId >= -1);
            Contract.Requires(formId < 255);

            if (!_database.ToString().Contains("Sql", StringComparison.OrdinalIgnoreCase)) return new System.Guid();

            Guid changesetGuid = Guid.NewGuid();

            Query insertQuery = _database.CreateQuery("INSERT INTO [Changesets] " + 
                "        (ChangesetID,  UpdateType,  UserName, MACADDR,  Description,  DestinationRecordID,  DestinationFormID, CheckinDate,        Version) " +
                "VALUES (@ChangesetId, @UpdateType, @User,    @MACADDR, @Description, @DestinationRecordID, @DestinationFormID, CURRENT_TIMESTAMP, @Version)");

            insertQuery.Parameters.Add(new QueryParameter("@ChangesetId", System.Data.DbType.String, _version));
            insertQuery.Parameters.Add(new QueryParameter("@UpdateType", System.Data.DbType.Int32, changesetType));
            insertQuery.Parameters.Add(new QueryParameter("@User", System.Data.DbType.String, _user));
            insertQuery.Parameters.Add(new QueryParameter("@MACADDR", System.Data.DbType.String, _macAddress));
            insertQuery.Parameters.Add(new QueryParameter("@Description", System.Data.DbType.String, description));
            insertQuery.Parameters.Add(new QueryParameter("@DestinationRecordID", System.Data.DbType.String, recordId));
            insertQuery.Parameters.Add(new QueryParameter("@DestinationFormID", System.Data.DbType.Int32, formId));
            insertQuery.Parameters.Add(new QueryParameter("@Version", System.Data.DbType.String, _version));

            try
            {
                if (transaction != null)
                {
                    _database.ExecuteNonQuery(insertQuery, transaction);
                }
                else
                {
                    int rows = _database.ExecuteNonQuery(insertQuery);
                    Contract.Assert(rows == 1);
                }
            }
            catch (Exception ex)
            {
                // don't let this crash the app, but make sure to log the issue
                DbLogger.Instance.Log(String.Format("Exception on changeset send: {0}", ex.Message));
            }

            return changesetGuid;
        }
    }
}
